Revert some of the bigger changes in c/s 9217 as these have been
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 14 Mar 2006 12:01:43 +0000 (13:01 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Tue, 14 Mar 2006 12:01:43 +0000 (13:01 +0100)
causing problems for a few people:
 1. HVM guests can now have page directories with unknown
    back pointers (I think this is the cause of problems that
    Jun Nakajima was seeing).
 2. L1 pagetable pinning requests are no longer ignored (may
    be the cause of problems Joe Bonasera was seeing).
 3. The PGT_va_mutable flag has been reintroduced, but for
    L1 pagetables only.

Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/mm.c
xen/include/asm-x86/mm.h

index e4af8e1263eeaecb63c4dca2e72634378611d4d5..54b1a52184db38f703fecbc529acc23f2c77846d 100644 (file)
@@ -778,6 +778,7 @@ static inline int l1_backptr(
 {
     unsigned long l2_backptr = l2_type & PGT_va_mask;
     ASSERT(l2_backptr != PGT_va_unknown);
+    ASSERT(l2_backptr != PGT_va_mutable);
     *backptr = 
         ((l2_backptr >> PGT_va_shift) << L3_PAGETABLE_SHIFT) | 
         (offset_in_l2 << L2_PAGETABLE_SHIFT);
@@ -792,6 +793,7 @@ static inline int l1_backptr(
 {
     unsigned long l2_backptr = l2_type & PGT_va_mask;
     ASSERT(l2_backptr != PGT_va_unknown);
+    ASSERT(l2_backptr != PGT_va_mutable);
     *backptr = ((l2_backptr >> PGT_va_shift) << L3_PAGETABLE_SHIFT) | 
         (offset_in_l2 << L2_PAGETABLE_SHIFT);
     return 1;
@@ -802,6 +804,7 @@ static inline int l2_backptr(
 {
     unsigned long l3_backptr = l3_type & PGT_va_mask;
     ASSERT(l3_backptr != PGT_va_unknown);
+    ASSERT(l3_backptr != PGT_va_mutable);
     *backptr = ((l3_backptr >> PGT_va_shift) << L4_PAGETABLE_SHIFT) | 
         (offset_in_l3 << L3_PAGETABLE_SHIFT);
     return 1;
@@ -1431,6 +1434,12 @@ void put_page_type(struct page_info *page)
                 nx &= ~PGT_validated;
             }
         }
+        else if ( unlikely((nx & (PGT_pinned|PGT_type_mask|PGT_count_mask)) == 
+                           (PGT_pinned|PGT_l1_page_table|1)) )
+        {
+            /* Page is now only pinned. Make the back pointer mutable again. */
+            nx |= PGT_va_mutable;
+        }
     }
     while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) );
 }
@@ -1513,16 +1522,24 @@ int get_page_type(struct page_info *page, unsigned long type)
                                 get_gpfn_from_mfn(page_to_mfn(page)));
                     return 0;
                 }
+                else if ( (x & PGT_va_mask) == PGT_va_mutable )
+                {
+                    /* The va backpointer is mutable, hence we update it. */
+                    nx &= ~PGT_va_mask;
+                    nx |= type; /* we know the actual type is correct */
+                }
                 else
                 {
                     ASSERT((type & PGT_va_mask) != (x & PGT_va_mask));
+                    ASSERT((type & PGT_va_mask) != PGT_va_mutable);
 #ifdef CONFIG_X86_PAE
                     /* We use backptr as extra typing. Cannot be unknown. */
                     if ( (type & PGT_type_mask) == PGT_l2_page_table )
                         return 0;
 #endif
                     /* Fixme: add code to propagate va_unknown to subtables. */
-                    if ( (type & PGT_type_mask) >= PGT_l2_page_table )
+                    if ( ((type & PGT_type_mask) >= PGT_l2_page_table) &&
+                         !shadow_mode_refcounts(page_get_owner(page)) )
                         return 0;
                     /* This table is possibly mapped at multiple locations. */
                     nx &= ~PGT_va_mask;
@@ -1801,17 +1818,22 @@ int do_mmuext_op(
         switch ( op.cmd )
         {
         case MMUEXT_PIN_L1_TABLE:
+            type = PGT_l1_page_table | PGT_va_mutable;
+            goto pin_page;
+
         case MMUEXT_PIN_L2_TABLE:
         case MMUEXT_PIN_L3_TABLE:
         case MMUEXT_PIN_L4_TABLE:
+            /* Ignore pinning of subdirectories. */
             if ( (op.cmd - MMUEXT_PIN_L1_TABLE) != (CONFIG_PAGING_LEVELS - 1) )
                 break;
 
+            type = PGT_root_page_table;
+
+        pin_page:
             if ( shadow_mode_refcounts(FOREIGNDOM) )
                 break;
 
-            type = PGT_root_page_table;
-
             okay = get_page_and_type_from_pagenr(mfn, type, FOREIGNDOM);
             if ( unlikely(!okay) )
             {
@@ -3350,7 +3372,7 @@ int ptwr_do_page_fault(struct domain *d, unsigned long addr,
     
     /* Get the L2 index at which this L1 p.t. is always mapped. */
     l2_idx = page->u.inuse.type_info & PGT_va_mask;
-    if ( unlikely(l2_idx == PGT_va_unknown) )
+    if ( unlikely(l2_idx >= PGT_va_unknown) )
         goto emulate; /* Urk! This L1 is mapped in multiple L2 slots! */
     l2_idx >>= PGT_va_shift;
 
index 74917fd2266bf2f688ea6e30d3b4363f82467315..8cfe942e8e202cc882106b76220f22e59ad0305b 100644 (file)
@@ -81,14 +81,18 @@ struct page_info
  /* The 11 most significant bits of virt address if this is a page table. */
 #define PGT_va_shift        16
 #define PGT_va_mask         (((1U<<11)-1)<<PGT_va_shift)
+ /* Is the back pointer still mutable (i.e. not fixed yet)? */
+#define PGT_va_mutable      (((1U<<11)-1)<<PGT_va_shift)
  /* Is the back pointer unknown (e.g., p.t. is mapped at multiple VAs)? */
-#define PGT_va_unknown      (((1U<<11)-1)<<PGT_va_shift)
+#define PGT_va_unknown      (((1U<<11)-2)<<PGT_va_shift)
 #elif defined(__x86_64__)
  /* The 27 most significant bits of virt address if this is a page table. */
 #define PGT_va_shift        32
 #define PGT_va_mask         ((unsigned long)((1U<<28)-1)<<PGT_va_shift)
+ /* Is the back pointer still mutable (i.e. not fixed yet)? */
+#define PGT_va_mutable      ((unsigned long)((1U<<28)-1)<<PGT_va_shift)
  /* Is the back pointer unknown (e.g., p.t. is mapped at multiple VAs)? */
-#define PGT_va_unknown      ((unsigned long)((1U<<28)-1)<<PGT_va_shift)
+#define PGT_va_unknown      ((unsigned long)((1U<<28)-2)<<PGT_va_shift)
 #endif
 
  /* 16-bit count of uses of this frame as its current type. */